home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 37
/
Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso
/
Aminet
/
dev
/
cross
/
Avr.lha
/
Atmel
/
Asm
/
src
/
asm.c
next >
Wrap
C/C++ Source or Header
|
2000-03-27
|
32KB
|
1,935 lines
/************************************************************************/
/* Atmel assembler V1.01 */
/* (C)2000 LJS */
/* This should compile on anything! */
/* */
/* 1)Removed NULL at end of constant strings */
/* 2)Shift Left/Right (< >) is now as for C ( << >> ) */
/* 3)Removed temporary file, now done to a buffer. */
/* 4)No upper limit on number of labels (except for avail RAM). */
/* 5)'def' added to allow small text replacements. */
/* 6)Maths precedence is now /*+-&|<> */
/* 7)Source files needed a new line at the end or else the last line */
/* would not be assembled, fixed. */
/************************************************************************/
#include<stdio.h>
#include<string.h>
typedef unsigned long ULONG;
typedef unsigned char BYTE;
#include "buff.h"
#include "errors.h"
/* #define DUMP_BUFFER "tmp1.tmp" */
#define CODEFILE "Atmel.txt"
#define MAXOPCODES 256
#define OPLENGTH 8
#define MAX_SR_LINE 16 /*16 bytes max on one S Record line*/
char *Errors[]={"OK",
"Bad constant",
"File error",
"Unrecognised opcode",
"Operand error",
"Out of range",
"Bad code generated",
"Use registers >15",
"Use registers 24, 26, 28 and 30",
"Redeclared label",
"Relative address must be even",
"Code must be at an even address",
"Can't open file for inclusion",
"Out of memory",
"Missing quote's",
"Division by zero",
"Missing brackets",
"Formula to complex"
};
#define D_ORG 0
#define D_END 1
#define D_EQU 2
#define D_INCL 3
#define D_NEWFILE 4
#define D_ENDNEW 5
#define D_CONSTB 6
#define D_CONSTW 7
#define D_DEFINE 8
char *Directives[]={"ORG",
"END",
"EQU",
"INCLUDE",
"FILE",
"ENDFILE",
"DB",
"DW",
"DEF",
NULL
};
struct ACode{char *Opcode;
char *Operand;
char *Code;
char *Flag;
};
struct DStack{ struct DStack *Last;
char *Data;
FILE *Handle;
long Line;
};
struct Labels{
struct Labels *Last;
char *Label;
int Address;
char Flag;
char *Macro;
};
struct ACode *Codes[MAXOPCODES];
int Error=0;
long LineNumber=0;
struct DStack *Files=NULL;
struct Labels *LabelStack = NULL;
BYTE SRBuffer[MAX_SR_LINE];
BYTE SROffset;
int SRIn=0;
#include "proto.h"
int main(int argc, char *argv[])
{
FILE *Infile;
MEMBUFF *Tempfile;
int Count;
char *Outfile, *Listfile=NULL;
printf(" Atmel cross assembler (C)2000 LJS By Lee Atkins.\n");
printf(" Version date "__DATE__"\n");
if(argc<2)
{
printf("Asm <source file> <output file> <list file>\n");
return 1;
}
if (argc>2)
{
Outfile=argv[2];
}
else
{
Outfile="a.out";
}
if (argc==4)
{
Listfile=argv[3];
}
for(Count=0; Count<MAXOPCODES; Count++)
{
Codes[Count]=NULL;
}
if(ParseCodes(CODEFILE))
{
PushFiles(argv[1],NULL);
Tempfile=OpenBuffer();
if(Tempfile!=NULL)
{
if(PreProcess(argv[1],Tempfile))
{
printf(" Assembling :%s\n Output on :%s\n",argv[1],Outfile);
if(Listfile)
{
printf(" List on :%s\n",Listfile);
}
Assemble(Tempfile,Outfile,Listfile,argv[1]);
}
if(Error)
{
printf(" File : %s\n",Files->Data);
printf(" Error %d, Line %ld %s.\n",Error,LineNumber,Errors[Error]);
}
else
{
printf(" Bytes used : %d\n",SRIn);
printf(" Assembled with no errors.\n");
}
#ifdef DUMP_BUFFER
BuffDump(DUMP_BUFFER,Tempfile);
#endif
KillBuffer(Tempfile);
}
else
{
printf(" Out of memory!\n");
}
}
else
{
printf(" Error parsing machine file!\n");
}
FreeCodes();
FreeLabelStack();
while(PopFiles());
return 1;
}
int ParseCodes(char *FileName)
{
FILE *Infile;
int Count=0, Part=0, OneOfFour=0;
char InText, InStr[36],Finished=0;
/*Gets code from code file FileName*/
Infile=fopen(FileName,"r");
if(Infile==NULL)
{
return 0;
}
do
{
do
{
do
{
InText=fgetc(Infile);
}while( (InText<33) && (InText!=EOF) );
if(InText==EOF)
{
fclose(Infile);
return 1;
}
if(InText=='*')
{
do
{
InText=fgetc(Infile);
}while( (InText!='*') && (InText!=EOF) );
if(InText==EOF)
{
fclose(Infile);
return 0;
}
}
}while(InText=='*');
Count=0;
do
{
InStr[Count++]=InText;
if(Count==36)
{
Count--;
fclose(Infile);
return 0;
}
InText=fgetc(Infile);
if(InText=='*')
{
fclose(Infile);
return 0;
}
}while(InText>32);
InStr[Count]=0; /*terminate*/
switch(OneOfFour)
{
case 0:
Codes[Part]=(struct ACode*)malloc(sizeof(struct ACode));
if(Codes[Part]==NULL)
{
Finished=2;
}
else
{
Codes[Part]->Operand=NULL;
Codes[Part]->Code=NULL;
Codes[Part]->Flag=NULL;
Codes[Part]->Opcode=(char*)malloc(strlen(InStr)+1);
if(Codes[Part]->Opcode==NULL)
{
Finished=2;
}
else
{
strcpy(Codes[Part]->Opcode,InStr);
OneOfFour++;
}
}
break;
case 1:
Codes[Part]->Operand=(char*)malloc(strlen(InStr)+1);
if(Codes[Part]->Operand==NULL)
{
Finished=2;
}
else
{
strcpy(Codes[Part]->Operand,InStr);
OneOfFour++;
}
break;
case 2:
Codes[Part]->Code=(char*)malloc(strlen(InStr)+1);
if(Codes[Part]->Code==NULL)
{
Finished=2;
}
else
{
strcpy(Codes[Part]->Code,InStr);
OneOfFour++;
}
break;
case 3:
Codes[Part]->Flag=(char*)malloc(strlen(InStr)+1);
if(Codes[Part]->Flag==NULL)
{
Finished=2;
}
else
{
strcpy(Codes[Part]->Flag,InStr);
OneOfFour=0;
Part++;
if(Part==MAXOPCODES)
{
Finished=2;
}
}
break;
} /*end switch*/
}while(!Finished);
fclose(Infile);
if(Finished==1)
{
return 1;
}
else
{
return 0;
}
}
int FreeCodes()
{
/*Frees Codes array*/
int Count;
for(Count=0; Count<MAXOPCODES; Count++)
{
if(Codes[Count]!=NULL)
{
if(Codes[Count]->Opcode!=NULL)
{
free(Codes[Count]->Opcode);
Codes[Count]->Opcode=NULL;
}
if(Codes[Count]->Operand!=NULL)
{
free(Codes[Count]->Operand);
Codes[Count]->Operand=NULL;
}
if(Codes[Count]->Code!=NULL)
{
free(Codes[Count]->Code);
Codes[Count]->Code=NULL;
}
if(Codes[Count]->Flag!=NULL)
{
free(Codes[Count]->Flag);
Codes[Count]->Flag=NULL;
}
free(Codes[Count]);
Codes[Count]=NULL;
}
}
return 1;
}
int PreProcess(char *Filename, MEMBUFF *Tempfile)
{
FILE *Infile;
char Line[128], First[128], Second[128], Third[128], *Ptr;
char TempStr[128], Flag;
int PC=0, Tmp, FileCount, WordPC=0, NewSz, Address;
struct Labels *Result;
LineNumber=0;
Infile=fopen(Filename,"r");
if(Infile==NULL)
{
printf("Can't open %s\n",Filename);
return 0;
}
FileCount=0;
do
{
while((!feof(Infile)) && (Error==0))
{
if(fgets(Line,128,Infile)==NULL) break;
LineNumber++;
StripComments(Line);
StripCrudd(Line);
StrUpr(Line);
Ptr=StrCpyChar(First,Line,' ');
Ptr=StrCpyChar(Second,Ptr,' ');
StrCpyChar(Third,Ptr,0);
RemoveSpace(First);
RemoveSpace(Second);
RemoveChar(Second,'.');
RemoveSpace(Third);
if(strlen(First))
{ /*Add label in stack*/
if(strcmp(Second,Directives[D_EQU])==0)
{
Replace(Third);
Address=StrToInt(Third);
Flag='E';
}
else if(strcmp(Second,Directives[D_DEFINE])==0)
{
Replace(Third);
Flag='M';
}
else
{
Address=WordPC;
Flag='A';
}
if(Error==0)
{
if(IsInStack(First))
{
Error=REPEATLABEL;
fclose(Infile);
return 0;
}
if(Flag=='E')
{
Second[0]=0;
Third[0]=0;
}
if(Flag == 'M')
{
Result = AddLabel(First, Address, Flag, Third);
Second[0]=0;
Third[0]=0;
}
else
{
Result = AddLabel(First, Address, Flag, NULL);
}
if( Result == NULL)
{
Error=MEM;
fclose(Infile);
return 0;
}
First[0]=0;
}
else
{
Error=0;
}
}
if(strlen(Second))
{
ProcessOperand(Third);
Error=0;
if( (Tmp=FindCode(Second)) !=MAXOPCODES )
{
NewSz=CodeLength(Tmp);
PC+=NewSz;
WordPC+=NewSz>>1;
}
else
{
/*could be a directive*/
Tmp=FindDirective(Second);
if(Directives[Tmp]!=NULL)
{
/*It is!*/
switch(Tmp)
{
case D_EQU:
break;
case D_DEFINE:
break;
case D_CONSTB:
NewSz=ConstantLength(Third,1);
PC+=NewSz;
WordPC+=NewSz>>1;
break;
case D_CONSTW:
NewSz=ConstantLength(Third,2);
PC+=NewSz;
WordPC+=NewSz>>1;
break;
case D_ORG:
PC=StrToInt(Third);
WordPC=PC;
break;
case D_NEWFILE:
PushFiles(Third,NULL);
LineNumber=0;
break;
case D_ENDNEW:
PopFiles();
break;
case D_INCL:
RemoveChar(Third,'"');
sprintf(TempStr," FILE \"%s\" \n",Third);
BuffPutS(TempStr,Tempfile);
PushFiles(Third,Infile); /*Save current file stuff*/
Infile=fopen(Third,"rb");
if(Infile==NULL)
{
Error=NOFILE;
Infile=PopFiles();
fclose(Infile);
return 0;
}
First[0]=0;
Second[0]=0;
Third[0]=0;
FileCount++;
LineNumber=0;
break;
case D_END:
First[0]=0;
Second[0]=0;
Third[0]=0;
break;
default:
Error=NOTOP;
break;
}/*end switch*/
}
else
{
Error=NOTOP;
}
}
}
sprintf(TempStr,"%s %s %s\n",First,Second,Third);
BuffPutS(TempStr,Tempfile);
}
fclose(Infile);
if( (FileCount) && (Error==0) )
{
BuffPutS(" ENDFILE",Tempfile);
Infile=PopFiles();
}
}while( (FileCount--) && (Error==0) );
if(Error==0) return 1;
return 0;
}
int FreeLabelStack(void)
{
struct Labels *Tmp;
while(LabelStack)
{
Tmp = LabelStack->Last;
if(LabelStack->Macro) free(LabelStack->Macro);
if(LabelStack->Label) free(LabelStack->Label);
free(LabelStack);
LabelStack = Tmp;
}
return 1;
}
struct Labels *AddLabel(char *Name, int Address, char Flag, char *Macro)
{
struct Labels *Tmp;
Tmp = (struct Labels*)malloc(sizeof(struct Labels));
if(Tmp != NULL)
{
Tmp->Last = LabelStack;
Tmp->Macro = NULL;
Tmp->Label = (char*)malloc(strlen(Name)+1);
if(Tmp->Label != NULL)
{
strcpy(Tmp->Label, Name);
Tmp->Address = Address;
Tmp->Flag = Flag;
if(Macro)
{
Tmp->Macro = (char*)malloc(strlen(Macro)+1);
if(Tmp->Macro != NULL)
{
strcpy(Tmp->Macro, Macro);
LabelStack = Tmp;
return Tmp;
}
}
else
{
LabelStack = Tmp;
return Tmp;
}
free(Tmp->Label);
}
free(Tmp);
}
return NULL;
}
int StripComments(char *Txt)
{
int Len=0;
while((*Txt!=';') && (Len<127) && (*Txt))
{
Txt++;
Len++;
if(*Txt=='"')
{
Txt++;
Len++;
while( (*Txt!='"') && (Len<127) && (*Txt) )
{
Txt++;
Len++;
}
if( (Len==127) || (*Txt!='"') )
{
Error=MISSINGQUOTE;
return 0;
}
}
}
*Txt=0;
return 1;
}
int CodeLength(int Code)
{
int Result;
if(Codes[Code]==NULL)
{
return 0;
}
Result=strlen(Codes[Code]->Code);
if(strchr(Codes[Code]->Code,'!'))
{
Result-=CountChar(Codes[Code]->Code,'!');
}
Result/=OPLENGTH;
return Result;
}
int CountChar(char *S, char C)
{
int Result=0;
while(*S)
{
if(*S==C)
{
Result++;
}
S++;
}
return Result;
}
char *StrCpyChar(char *Dest, char *Src, char Stop)
{
char C;
if(Src==NULL)
{
*Dest=0;
return NULL;
}
do
{
C=*Src;
Src++;
if(C==0)
{
*Dest=0;
return NULL;
}
if(C==Stop)
{
C=0;
}
*Dest=C;
Dest++;
}while(C);
while(*Src==Stop)
{
Src++;
}
return Src;
}
int StripCrudd(char *S)
{
while(*S)
{
if(*S<32)
{
*S=32;
}
else if(*S==':')
{
*S=' ';
}
S++;
}
return 1;
}
int RemoveChar(char *S, char T)
{
/*Removes a character from a string*/
char *Temp;
Temp=S;
while(*S)
{
if(*S==T)
{
*S=' ';
}
S++;
}
RemoveSpace(Temp);
return 1;
}
int RemoveSpace(char *S)
{
/*Removes space from a string*/
char *T;
while(*S)
{
if(*S==' ')
{
T=S;
while(*T)
{
*T=*(T+1);
T++;
}
}
else
{
S++;
}
}
return 1;
}
int IsInStack(char *Str)
{
struct Labels *Tmp;
Tmp = LabelStack;
while(Tmp)
{
if(strcmp(Str,Tmp->Label)==0)
{
return 1;
}
Tmp = Tmp->Last;
}
return 0;
}
int FindCode(char *Str)
{
int Count;
for (Count=0; Count<MAXOPCODES; Count++)
{
if(Codes[Count]!=NULL)
{
if(strcmp(Str,Codes[Count]->Opcode)==0)
{
return Count;
}
}
}
return Count;
}
int FindDirective(char *Str)
{
int Count=0;
while(Directives[Count])
{
if(strcmp(Str,Directives[Count])==0)
{
return Count;
}
Count++;
}
return Count;
}
int ProcessOperand(char *Str)
{
char *Ptr,Left[128],Right[128],Comma;
Left[0]=0;
Right[0]=0;
Ptr=Str;
Comma=0;
while( (*Str!=',') && (*Str) )
{
Str++;
}
if(*Str==',')
{
*Str=0;
Str++;
Comma=1;
}
else
{
Str=Ptr;
}
strcpy(Left,Ptr);
strcpy(Right,Str);
Replace(Left);
strcpy(Ptr,Left);
if(Comma)
{
Replace(Right);
strcat(Ptr,",");
strcat(Ptr,Right);
}
return 0;
}
int Replace(char *Str)
{
int Ret;
char Work[128],Returned[128], *Sep="+-*/&|<>)",*Tmp;
char *Orig, *Op=" ", *StrIn, BitOfMath=0;
Work[0]=0;
Orig=Str;
StrIn=Str;
while(*Str)
{
if(*Str=='(')
{
*Op=*Str;
strcat(Work,Op);
Orig++;
}
else
{
Tmp=Sep;
while( (*Tmp) && (*Tmp!=*Str))
{
Tmp++;
}
if(*Tmp)
{
/*Found a maths operator*/
BitOfMath=1;
*Str=0;
ReplaceLabels(Orig,Returned);
strcat(Work,Returned);
*Op=*Tmp;
strcat(Work,Op);
Orig=Str+1;
}
}
Str++;
}
ReplaceLabels(Orig,Returned);
strcat(Work,Returned);
if(BitOfMath)
{
Ret=Math(Work);
if(!Error)
{
sprintf(StrIn,"$%X",Ret);
}
else
{
strcpy(StrIn,Work);
}
}
else
{
strcpy(StrIn,Work);
}
return 0;
}
int ReplaceLabels(char *Str, char *Res)
{
struct Labels *Tmp;
strcpy(Res,Str);
Tmp = LabelStack;
while(Tmp)
{
if(Tmp->Label!=NULL)
{
if(strcmp(Str, Tmp->Label)==0)
{
if(Tmp->Macro)
{
strcpy(Res,Tmp->Macro);
}
else
{
sprintf(Res,"$%04X",Tmp->Address);
}
return 0;
}
}
Tmp = Tmp->Last;
}
return 0;
}
int StrToInt(char *Str)
{
/*Converts an asciiz number string into an int*/
/*Detects input type as being in hex,dec or bin*/
/*$aa, 0aaH is hex, %1001, 1001b is binary*/
int Result;
StrUpr(Str);
if(strchr(Str,'H')!=NULL)
{
Result=HexToInt(Str);
}
else if(strchr(Str,'$')!=NULL)
{
Result=HexToInt(Str);
}
else if(strchr(Str,'%')!=NULL)
{
Result=BinToInt(Str);
}
else if(strchr(Str,'B')!=NULL)
{
Result=BinToInt(Str);
}
else
{
if(!Validate(Str,"-+0123456789"))
{
Error=CONSTANT;
return 0;
}
Result=atoi(Str);
}
return Result;
}
int HexToInt(char *Str)
{
/* converts a hex string into an int*/
int Result=0,Weight=1,C=1;
char *Tmp;
Tmp=Str;
if(strchr(Str,'$')!=NULL)
{
Tmp=strchr(Str,'$');
Tmp++;
}
else
{
while(*Str)
{
Str++;
}
while(*Str!='H')
{
Str--;
}
*Str=0;
}
Str=Tmp+strlen(Tmp);
if(!Validate(Tmp,"0123456789ABCDEF"))
{
Error=CONSTANT;
return 0;
}
while(Str!=Tmp)
{
Str--;
Result+=(*Str<'A' ? (*Str-'0'):(10+(*Str-'A')) ) * Weight;
Weight<<=4;
C++;
}
return Result;
}
int Validate(char *Str, char *Comp)
{
/*Checks a string for invalid characters*/
char *Tmp;
BYTE Result=0;
Tmp=Comp;
while(*Str)
{
Comp=Tmp;
Result=0;
while(*Comp)
{
if(*Str==*Comp)
{
Result=1;
}
Comp++;
}
if(Result==0)
{
return 0;
}
Str++;
}
return 1;
}
int BinToInt(char *Str)
{
/*Converts a binary string into an int*/
int Result=0,Weight=1;
char *Tmp;
Tmp=Str;
if(strchr(Str,'%')!=NULL)
{
Tmp=strchr(Str,'%');
Tmp++;
}
else
{
while(*Str)
{
Str++;
}
while(*Str!='B')
{
Str--;
}
*Str=0;
}
Str=Tmp+strlen(Tmp);
if(!Validate(Tmp,"01"))
{
Error=CONSTANT;
return 0;
}
while(Str!=Tmp)
{
Str--;
Result+=(*Str-'0') * Weight;
Weight<<=1;
}
return Result;
}
int Assemble(MEMBUFF *Tempfile, char *Out, char *List, char *Name)
{
FILE *Outfile=NULL, *SRecord=NULL;
int Count,Found,Replaced,Tmp,PC=0,OldPC=0,PrintPC=0, SRPC=0,CodePC=0;
char Line[128], First[128], Second[128], Repeat[128], *Ptr;
char OrigFirst[128], OrigSecond[128], Third[128];
char Code[33], Map[8],*Indirect,*Post,*Pre, *Temp, Flag;
ULONG CodeData, Swap;
int Address;
LineNumber=0;
BuffRewind(Tempfile);
if(List)
{
Outfile=fopen(List,"wb");
if(Outfile==NULL)
{
Error=FILE_ERROR;
return 0;
}
}
SRecord=fopen(Out,"w");
if(SRecord==NULL)
{
fclose(Outfile);
Error=FILE_ERROR;
return 0;
}
StartSRecord(SRecord,Name);
do
{
do
{
BuffGetS(Line,128,Tempfile);
LineNumber++;
StripCrudd(Line);
StrUpr(Line);
Ptr=StrCpyChar(First,Line,' ');
Ptr=StrCpyChar(Second,Ptr,' ');
StrCpyChar(Third,Ptr,0);
RemoveSpace(First);
RemoveSpace(Second);
RemoveSpace(Third);
}while((strlen(Second)==0) && (!BuffEOF(Tempfile)));
if(strlen(Second)==0)
{
FinishSRecord(SRecord,SRPC-1);
if(Outfile)
{
DumpLabels(Outfile);
fclose(Outfile);
}
fclose(SRecord);
return 1;
}
strcpy(OrigFirst,Second); /*Save for output to list file*/
strcpy(OrigSecond,Third);
if(!strchr(Third,'"')) /*Test for a text string*/
{
ProcessOperand(Third);
/*Look for code*/
Indirect=strchr(Third,'X');
if(Indirect==NULL)
{
Indirect=strchr(Third,'Y');
}
if(Indirect==NULL)
{
Indirect=strchr(Third,'Z');
}
}
else
{
Indirect=NULL;
}
if(Indirect!=NULL)
{
Error=0; /*These will produce an error in the maths bits*/
Post=strchr(Third,'+');
Pre=strchr(Third,'-');
if(Post)
{
if(Post<Indirect)
{
Pre=Post;
Post=NULL;
}
else if(Post>Indirect)
{
Pre=NULL;
}
}
else if(Pre)
{
if(Pre>Indirect)
{
Post=Pre;
Pre=NULL;
}
else if(Pre<Indirect)
{
Post=NULL;
}
}
}
do
{
Count=0;
Found=0;
Replaced=0;
while((Count<MAXOPCODES) && (Codes[Count]) && (!Found))
{
if(strcmp(Codes[Count]->Opcode,Second)==0)
{
if(Indirect)
{
Temp=strchr(Codes[Count]->Operand,*Indirect);
if(Temp!=NULL)
{
if(Pre)
{
if(*(Temp-1)==*Pre)
{
Found=1;
}
}
else if(Post)
{
if(*(Temp+1)==*Post)
{
Found=1;
}
}
else if(strchr(Third,*Temp))
{
Found=1;
}
}
}
else
{
Found=1;
}
}
if(!Found)
{
Count++;
}
}
if(Found)
{
if(*Codes[Count]->Flag=='A')
{
strcpy(Second,Codes[Count]->Flag+1);
strcpy(Repeat,Third);
strcat(Third,",");
strcat(Third,Repeat);
Replaced=1;
}
}
}while(Replaced);
if(!Found)
{
if(!AsmDirective(Second))
{
printf("Unrecognised Opcode.\n");
Error=NOTOP;
fclose(Outfile);
fclose(SRecord);
return 0;
}
else
{
Tmp=FindDirective(Second);
if(Directives[Tmp]!=NULL)
{
/*It is!*/
switch(Tmp)
{
case D_CONSTB:
if(Outfile)
{
fprintf(Outfile,"%ld\t",LineNumber);
fprintf(Outfile,"%04X ",PrintPC);
}
PutConstants(Outfile,SRecord,Third,&SRPC,1);
if(Outfile)
{
fprintf(Outfile,"\t%s %s\n",OrigFirst,OrigSecond);
}
PC=SRPC;
PrintPC=SRPC>>1;
CodePC=PrintPC;
break;
case D_CONSTW:
if(Outfile)
{
fprintf(Outfile,"%ld\t",LineNumber);
fprintf(Outfile,"%04X ",PrintPC);
}
PutConstants(Outfile,SRecord,Third,&SRPC,2);
if(Outfile)
{
fprintf(Outfile,"\t%s %s\n",OrigFirst,OrigSecond);
}
PC=SRPC;
PrintPC=SRPC>>1;
CodePC=PrintPC;
break;
case D_ORG:
FlushSRBuffer(SRecord,SRPC-1);
PC=StrToInt(Third);
PrintPC=PC;
CodePC=PC;
SRPC=PC<<1;
break;
case D_NEWFILE:
PushFiles(Third,NULL);
LineNumber=0;
break;
case D_ENDNEW:
PopFiles();
LineNumber++;
break;
case D_EQU:
Replace(Third);
Address=StrToInt(Third);
Flag='E';
if(IsInStack(First))
{
Error=REPEATLABEL;
}
if(AddLabel(First, Address, Flag, NULL)==NULL)
{
Error=MEM;
}
break;
}
}
}
}
else
{
strcpy(Code,Codes[Count]->Code);
strcpy(Map,Codes[Count]->Operand);
OldPC=PC;
PC+=CodeLength(Count); /*Next address*/
CodePC+=(PC-OldPC)>>1;
CodeData=CreateCode(Code,Map,Third,Codes[Count]->Flag,CodePC);
if(Outfile)
{
fprintf(Outfile,"%ld\t",LineNumber);
fprintf(Outfile,"%04X %04lX ",PrintPC,CodeData);
PrintPC+=(PC-OldPC)>>1;
fprintf(Outfile,"\t%s %s\n",OrigFirst,OrigSecond);
}
if( (PC-OldPC)==4)
{
PutSRBuffer(SRecord,CodeData>>16,SRPC);
PutSRBuffer(SRecord,(CodeData>>24)&255,SRPC+1);
PutSRBuffer(SRecord,CodeData&255,SRPC+2);
PutSRBuffer(SRecord,CodeData>>8,SRPC+3);
}
else
{
PutSRBuffer(SRecord,CodeData&255,SRPC);
PutSRBuffer(SRecord,CodeData>>8,SRPC+1);
}
if(SRPC&1)
{
printf("Asm error.\n");
Error=ALLIGNMENT;
}
SRPC+=(PC-OldPC);
}
}while( (!BuffEOF(Tempfile)) && (Error==0) );
FinishSRecord(SRecord,SRPC);
if(Outfile)
{
DumpLabels(Outfile);
fclose(Outfile);
}
fclose(SRecord);
return 1;
}
ULONG CreateCode(char *Code, char *Map, char *Operand, char *Flag,int PC)
{
char Part[128], *Temp, MapPart[128], *MapTemp;
int Count, Work, Steps, Step,Len;
ULONG Result;
if(strcmp(Map,"-")==0)
{
Result=BinToULong(Code);
return Result;
}
memset(MapPart,0,128);
Temp=Code;
if(strchr(Map,',')!=NULL)
{
Steps=2;
}
else
{
Steps=1;
}
for(Step=0; Step<Steps; Step++)
{
Code=Temp;
if (Validate(Code,"01"))
{
break;
}
Len=strlen(Code);
Count=0;
MapTemp=Map;
while((*Operand) && (*Operand!=','))
{
Part[Count]=*Operand;
MapPart[Count]=*Map;
Count++;
Operand++;
Map++;
}
Part[Count]=0;
MapPart[Count]=0;
Map=MapTemp;
if(*Map=='R')
{
if(Part[0]=='R')
{
Work=StrToInt(&Part[1]);
if(*Flag=='S')
{
if(Work<16)
{
Error=REG16;
return 0;
}
Work-=16;
}
if(*Flag=='U')
{
if( (Work<24) || (Work&1) )
{
Error=UPPERREGS;
return 0;
}
Work=(Work>>1)&3;
}
Map++;
}
else
{
Error=WRONGOP;
return 0;
}
}
else if(*Map=='k')
{
if( (strchr(Operand,',')!=NULL) && (Steps==1) )
{
Error=WRONGOP;
return 0;
}
Work=StrToInt(Part);
if(*Flag=='R')
{
Work=(Work-PC);
if((Work>63) || (Work<-64))
{
Error=RANGE;
return 0;
}
Work&=127;
}
else if(*Flag=='L')
{
Work=(Work-PC);
Work&=4095;
}
else if(*Flag=='N')
{
Work&=0xFFFF;
}
}
else if(*Map=='K')
{
Work=StrToInt(Part);
}
else if(MapPart[2]=='q')
{
Work=StrToInt(&Part[2]);
Map+=2;
}
else
{
if(!Validate(MapPart,"XYZ,+-"))
{
Work=StrToInt(Part);
}
else
{
Work=0;
}
}
Code+=(Len-1);
while(Len)
{
if( (*Code=='!') && (*(Code+1)!='K') )
{
Code++;
if(*Code=='1')
{
*Code='0';
}
else
{
*Code='1';
}
Code--;
*Code=' ';
RemoveSpace(Code);
}
if(*Code==*Map)
{
if(Work&1)
{
*Code='1';
}
else
{
*Code='0';
}
Work>>=1;
}
if(*Code=='X') /*Don't care bit*/
{
*Code='0';
}
Code--;
Len--;
}
if(Work>0) /*-ve numbers are ok!*/
{
Error=RANGE;
return 0;
}
Operand++;
while( (*Map) && (*Map!=',') )
{
Map++;
}
Map++;
}
Code=Temp;
Result=BinToULong(Code);
return Result;
}
ULONG BinToULong(char *Str)
{
/*Converts binary to ulong!*/
int Len;
ULONG Weight=1,Result=0;
StripDontCare(Str);
Len=strlen(Str);
Str+=Len-1;
while(Len)
{
if(Weight==0)
{
Error=RANGE;
return 0;
}
if(*Str=='1')
{
Result|=Weight;
}
else if(*Str!='0')
{
Error=BADCODE;
return 0;
}
Weight<<=1;
Str--;
Len--;
}
return Result;
}
int StripDontCare(char *Str)
{
/*Replaces 'X' with '0' in a string*/
while(*Str)
{
if(*Str=='X')
{
*Str='0';
}
Str++;
}
return 1;
}
int AsmDirective(char *Str)
{
int Count=0;
while(Directives[Count]!=NULL)
{
if(strcmp(Str,Directives[Count])==0)
{
return 1;
}
Count++;
}
return 0;
}
int PushFiles(char *Str, FILE *H)
{
struct DStack *Temp;
if(Files==NULL)
{
Files=(struct DStack*)malloc(sizeof(struct DStack));
if(Files==NULL)
{
Error=MEM;
return 0;
}
Files->Last=NULL;
Files->Data=(char*)malloc(strlen(Str)+1);
if(Files->Data==NULL)
{
Error=MEM;
return 0;
}
Files->Line=LineNumber;
Files->Handle=H;
strcpy(Files->Data,Str);
}
else
{
Temp=Files;
Files=(struct DStack*)malloc(sizeof(struct DStack));
if(Files==NULL)
{
Error=MEM;
Files=Temp;
return 0;
}
Files->Last=Temp;
Files->Data=(char*)malloc(strlen(Str)+1);
if(Files->Data==NULL)
{
Error=MEM;
return 0;
}
strcpy(Files->Data,Str);
Files->Line=LineNumber;
Files->Handle=H;
}
return 1;
}
FILE *PopFiles(void)
{
struct DStack *Temp;
FILE *TempFile;
if(Files)
{
if(Files->Data!=NULL)
{
free(Files->Data);
Files->Data=NULL;
}
LineNumber=Files->Line;
TempFile=Files->Handle;
Temp=Files->Last;
free(Files);
Files=Temp;
return TempFile;
}
return NULL;
}
int StartSRecord(FILE *File, char *Name)
{
int Checksum, Temp;
char *Orig;
Orig=Name;
fprintf(File,"S0");
Temp=0;
while( (*Name) && (*Name!='.') )
{
Temp++;
Name++;
}
Name=Orig;
Temp+=3; /*+address +checksum*/
Checksum=Temp;
fprintf(File,"%02X",Temp);
fprintf(File,"0000");
while( (*Name) && (*Name!='.') )
{
fprintf(File,"%02X",*Name);
Checksum+=*Name;
Name++;
}
Checksum=~Checksum;
fprintf(File,"%02X\n",(Checksum&255));
SROffset=0;
return 1;
}
int PutSRBuffer(FILE *File, BYTE Data, int PC)
{
SRIn++;
SRBuffer[SROffset]=Data;
SROffset++;
if(SROffset==MAX_SR_LINE)
{
FlushSRBuffer(File,PC);
}
return 1;
}
int FlushSRBuffer(FILE *Outfile,int PC)
{
int C,Count;
int Checksum;
Count=SROffset;
if(Count==0)
{
return 1;
}
fprintf(Outfile,"S1");
fprintf(Outfile,"%02X",Count+3); /*+3 for checksum and address*/
Checksum=Count+3;
fprintf(Outfile,"%04X",PC-Count+1);
Checksum+=((PC-Count+1)>>8);
Checksum+=((PC-Count+1)&255);
for(C=0; C<Count; C++)
{
fprintf(Outfile,"%02X",SRBuffer[C]);
Checksum+=SRBuffer[C];
}
Checksum=~Checksum;
fprintf(Outfile,"%02X\n",(Checksum&255));
SROffset=0;
return 1;
}
int FinishSRecord(FILE *F,int PC)
{
FlushSRBuffer(F,PC);
fprintf(F,"S9030000FC\n");
return 1;
}
int ConstantLength(char *S, BYTE Size)
{
char Work[128];
int Os,Result=0;
do
{
Os=0;
while((*S) && (*S!=','))
{
Work[Os]=*S;
Os++;
if(Os==128)
{
Os--;
}
S++;
}
Work[Os]=0;
if(*S==',')
{
S++;
}
Os=0;
if(Work[Os]=='"')
{
Os++;
while((Work[Os]!='"') && (Work[Os]))
{
Result+=Size; /*Do we want word long chars? !!!!*/
Os++;
}
/* Result+=Size; */ /*For the NULL, Dont put a null*/
}
else
{
Result+=Size;
}
}while(*S);
return Result;
}
int PutConstants(FILE *List,FILE *Out,char *S,int *PC, BYTE Size)
{
char Work[128];
unsigned int Temp;
int Os, Width=0;
do
{
Os=0;
while((*S) && (*S!=','))
{
Work[Os]=*S;
Os++;
if(Os==128)
{
Os--;
}
S++;
}
Work[Os]=0;
if(*S==',')
{
S++;
}
Os=0;
if( (Work[Os]=='"') && (Size==1) )
{
Os++;
while((Work[Os]!='"') && (Work[Os]))
{
PutSRBuffer(Out,(BYTE)Work[Os],*PC);
if(List)
{
fprintf(List,"%02X",Work[Os]);
Width++;
if(Width==2)
{
Width=0;
fprintf(List,"\n ");
}
}
*PC=*PC+1;
Os++;
}
/* Dont stuff in a null !!!
**PutSRBuffer(Out,0,*PC);
***PC=*PC+1;
**if(List)
**{
** fprintf(List,"00");
**}
*/
}
else
{
Temp=StrToInt(Work);
if(List)
{
fprintf(List,"%02X",Temp&255);
Width++;
if(Width==2)
{
Width=0;
fprintf(List,"\n ");
}
}
PutSRBuffer(Out,Temp&255,*PC);
*PC=*PC+1;
if(Size==2)
{
if(List)
{
fprintf(List,"%02X",Temp>>8);
Width++;
if(Width==2)
{
Width=0;
fprintf(List,"\n ");
}
}
PutSRBuffer(Out,Temp>>8,*PC);
*PC=*PC+1;
}
}
}while(*S);
return 1;
}
void StrUpr(char *String)
{
BYTE TextCount=0;
while(*String)
{
if(*String=='"') /*Dont upper constant text*/
{
TextCount=~TextCount;
}
if ( ('a' <= *String) && (*String <= 'z') && (TextCount==0) )
{
*String= *String + 'A' - 'a';
}
String++;
}
}
void DumpLabels(FILE *List)
{
struct Labels *Tmp;
fprintf(List,"\n\n");
Tmp = LabelStack;
while(Tmp)
{
if(Tmp->Label!=NULL)
{
if(Tmp->Flag=='E')
{
fprintf(List,"%s\t\t$%04X\tE\n",Tmp->Label,Tmp->Address);
}
else if(Tmp->Flag == 'M')
{
fprintf(List,"%s\t\t%s\tM\n",Tmp->Label,Tmp->Macro);
}
else
{
fprintf(List,"%s\t\t$%04X\tL\n",Tmp->Label,Tmp->Address);
}
}
Tmp = Tmp->Last;
}
}